package cn.dansj.common.utils.json;

import cn.dansj.common.utils.transfer.ArrayUtils;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.*;

import java.io.IOException;
import java.io.Serializable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

public class UniversalDeserializer<T> extends JsonDeserializer<T> {
    // 高性能缓存
    private static final ConcurrentMap<Method, MethodHandle> METHOD_HANDLE_CACHE = new ConcurrentHashMap<>();
    private static final ConcurrentMap<Constructor<?>, MethodHandle> CONSTRUCTOR_HANDLE_CACHE = new ConcurrentHashMap<>();
    private static final ConcurrentMap<ClassPair, Boolean> TYPE_COMPATIBILITY_CACHE = new ConcurrentHashMap<>();
    private static final ConcurrentMap<Class<?>, StringConverter> STRING_CONVERTER_CACHE = new ConcurrentHashMap<>();

    // 黑名单：低特异性类型
    private static final Set<Class<?>> LOW_SPECIFICITY_BLACKLIST = ArrayUtils.asSet(Object.class, Serializable.class, Cloneable.class);

    // 预热缓存：常用类型
    static {
        // 预加载常用类型转换器
        Class<?>[] commonTypes = {String.class, int.class, Integer.class, long.class, Long.class, double.class, Double.class, float.class, Float.class,
                boolean.class, Boolean.class, short.class, Short.class, byte.class, Byte.class, char.class, Character.class, BigDecimal.class, BigInteger.class};

        for (Class<?> type : commonTypes) {
            StringConverter converter = createStringConverter(type);
            if (converter != null) STRING_CONVERTER_CACHE.put(type, converter);
        }

        // 预计算常用类型兼容性
        Class<?>[][] compatiblePairs = {
                {int.class, Integer.class}, {Integer.class, int.class},
                {long.class, Long.class}, {Long.class, long.class},
                {double.class, Double.class}, {Double.class, double.class},
                {float.class, Float.class}, {Float.class, float.class},
                {boolean.class, Boolean.class}, {Boolean.class, boolean.class},
                {short.class, Short.class}, {Short.class, short.class},
                {byte.class, Byte.class}, {Byte.class, byte.class},
                {char.class, Character.class}, {Character.class, char.class}
        };

        for (Class<?>[] pair : compatiblePairs) {
            ClassPair key = new ClassPair(pair[0], pair[1]);
            TYPE_COMPATIBILITY_CACHE.put(key, true);
        }
    }

    private final Creator<T>[] creators;
    private final Creator<T> stringCreator;
    private final Map<Class<?>, Creator<T>> exactMatchCache = new ConcurrentHashMap<>();
    private final Class<T> targetClass;
    private final boolean hasNumberCreator;
    private final boolean hasBooleanCreator;
    private final boolean hasCollectionCreator;

    public UniversalDeserializer(Class<T> vc) {
        this.targetClass = vc;
        this.creators = initCreators();
        this.stringCreator = findStringCreator();

        // 分析创建器能力
        boolean hasNum = false;
        boolean hasBool = false;
        boolean hasColl = false;

        for (Creator<T> c : creators) {
            Class<?> paramType = c.getParameterType();
            if (isNumericType(paramType)) hasNum = true;
            if (paramType == boolean.class || paramType == Boolean.class) hasBool = true;
            if (Collection.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) hasColl = true;
        }

        this.hasNumberCreator = hasNum;
        this.hasBooleanCreator = hasBool;
        this.hasCollectionCreator = hasColl;
    }

    @SuppressWarnings("unchecked")
    private Creator<T>[] initCreators() {
        List<Creator<T>> creatorList = new ArrayList<>(4);
        // 1. 扫描带有@JsonCreator注解的创建器
        scanAnnotatedCreators(creatorList);
        // 2. 如果没有找到注解的创建器，扫描所有符合条件的创建器
        if (creatorList.isEmpty()) scanAllCreators(creatorList);
        // 3. 应用黑名单过滤低特异性创建器
        applyBlacklist(creatorList);
        // 4. 为创建器排序
        sortCreators(creatorList);
        // 预填充精确匹配缓存
        for (Creator<T> creator : creatorList) exactMatchCache.put(creator.getParameterType(), creator);
        return creatorList.toArray(new Creator[0]);
    }

    // 应用黑名单过滤低特异性创建器
    private void applyBlacklist(List<Creator<T>> creatorList) {
        Iterator<Creator<T>> it = creatorList.iterator();
        while (it.hasNext()) {
            Creator<T> creator = it.next();
            Class<?> paramType = creator.getParameterType();
            // 检查是否在黑名单中或特异性太低
            if (LOW_SPECIFICITY_BLACKLIST.contains(paramType) || getParameterSpecificity(paramType) < 50) it.remove();
        }
    }

    private void scanAnnotatedCreators(List<Creator<T>> creatorList) {
        // 扫描构造器
        for (Constructor<?> constructor : targetClass.getDeclaredConstructors()) {
            if (constructor.isAnnotationPresent(JsonCreator.class) && constructor.getParameterCount() == 1) {
                creatorList.add(new ConstructorCreator<>(constructor));
            }
        }
        // 扫描静态工厂方法
        for (Method method : targetClass.getDeclaredMethods()) {
            if (method.isAnnotationPresent(JsonCreator.class) && Modifier.isStatic(method.getModifiers()) && method.getReturnType().isAssignableFrom(targetClass) && method.getParameterCount() == 1) {
                creatorList.add(new MethodCreator<>(method));
            }
        }
    }

    private void scanAllCreators(List<Creator<T>> creatorList) {
        // 扫描单参数构造器
        for (Constructor<?> constructor : targetClass.getDeclaredConstructors()) {
            if (constructor.getParameterCount() == 1) {
                creatorList.add(new ConstructorCreator<>(constructor));
            }
        }

        // 扫描单参数静态工厂方法
        for (Method method : targetClass.getDeclaredMethods()) {
            if (Modifier.isStatic(method.getModifiers()) && method.getReturnType().isAssignableFrom(targetClass) && method.getParameterCount() == 1) {
                creatorList.add(new MethodCreator<>(method));
            }
        }
    }

    private void sortCreators(List<Creator<T>> creatorList) {
        // 排序规则：构造器优先，然后按参数类型特异性排序 // 构造器优先 // 特异性高的在前
        creatorList.sort(Comparator.comparingInt((Creator<T> c) -> c instanceof ConstructorCreator ? 0 : 1).thenComparingInt(c -> -getParameterSpecificity(c.getParameterType())));
    }

    private int getParameterSpecificity(Class<?> paramType) {
        int score = 0;

        if (paramType.isPrimitive()) {
            score += 100; // 原始类型优先级高
        } else if (Number.class.isAssignableFrom(paramType)) {
            score += 80; // 数字类型
        } else if (paramType == String.class) {
            score += 60; // 字符串类型
        }

        // 具体类比接口优先级高
        if (!paramType.isInterface()) {
            score += 50;
        }

        // 类的层级深度
        Class<?> current = paramType;
        while (current != null) {
            score += 10;
            current = current.getSuperclass();
        }

        return score;
    }

    private Creator<T> findStringCreator() {
        for (Creator<T> creator : creators) {
            if (creator.getParameterType() == String.class) {
                return creator;
            }
        }
        return null;
    }

    @Override
    public T deserialize(JsonParser p, DeserializationContext context) throws IOException {
        JsonToken token = p.currentToken();
        if (token == null) {
            token = p.nextToken();
            if (token == null) return null;
        }

        Object value = getValueBasedOnToken(p, token, context);
        if (value == null) return null;

        Class<?> valueClass = value.getClass();

        // 1. 尝试精确匹配（使用缓存）
        Creator<T> creator = exactMatchCache.get(valueClass);
        if (creator != null) return invokeCreator(creator, value, p, context);
        // 路径剪枝：检查当前值类型是否可能被处理
        if (!isValueTypeSupported(valueClass, token)) {
            throw context.instantiationException(targetClass, "Value type not supported by any creator: " + valueClass.getName());
        }
        // 2. 尝试类型兼容匹配（使用缓存）
        for (Creator<T> c : creators) {
            if (isCompatibleType(c.getParameterType(), valueClass)) return invokeCreator(c, value, p, context);
        }

        // 3. 尝试原始类型兼容
        for (Creator<T> c : creators) {
            if (isPrimitiveCompatible(c.getParameterType(), valueClass)) return invokeCreator(c, value, p, context);
        }

        // 4. 尝试字符串转换（优先使用预查找的字符串创建器）
        if (value instanceof String) return tryStringConversion((String) value, p, context);

        throw context.instantiationException(targetClass, String.format("No suitable creator found for value: %s [type: %s]", value, valueClass.getName()));
    }

    // 路径剪枝：检查当前值类型是否可能被处理
    private boolean isValueTypeSupported(Class<?> valueClass, JsonToken token) {
        if (valueClass == String.class) return true;
        switch (token) {
            case VALUE_NUMBER_INT:
            case VALUE_NUMBER_FLOAT:
                return hasNumberCreator;
            case VALUE_TRUE:
            case VALUE_FALSE:
                return hasBooleanCreator;
            case START_ARRAY:
            case START_OBJECT:
                return hasCollectionCreator;
            default:
                return true;
        }
    }

    private boolean isNumericType(Class<?> type) {
        return Number.class.isAssignableFrom(type) || type.isPrimitive() && type != boolean.class && type != char.class;
    }

    private boolean isCompatibleType(Class<?> targetType, Class<?> valueType) {
        ClassPair key = new ClassPair(targetType, valueType);
        Boolean cached = TYPE_COMPATIBILITY_CACHE.get(key);
        if (cached != null) return cached;
        boolean result = targetType.isAssignableFrom(valueType) || isWrapperCompatible(targetType, valueType);
        TYPE_COMPATIBILITY_CACHE.putIfAbsent(key, result);
        return result;
    }

    private boolean isWrapperCompatible(Class<?> targetType, Class<?> valueType) {
        if (targetType.isPrimitive()) {
            return valueType == getWrapperType(targetType);
        } else if (valueType.isPrimitive()) {
            return targetType == getWrapperType(valueType);
        }
        return false;
    }

    private Class<?> getWrapperType(Class<?> primitiveType) {
        if (primitiveType == int.class) return Integer.class;
        if (primitiveType == long.class) return Long.class;
        if (primitiveType == double.class) return Double.class;
        if (primitiveType == float.class) return Float.class;
        if (primitiveType == boolean.class) return Boolean.class;
        if (primitiveType == short.class) return Short.class;
        if (primitiveType == byte.class) return Byte.class;
        if (primitiveType == char.class) return Character.class;
        return null;
    }

    private boolean isPrimitiveCompatible(Class<?> targetType, Class<?> valueType) {
        if (!targetType.isPrimitive()) return false;
        if (targetType == int.class) return valueType == Integer.class;
        if (targetType == long.class) return valueType == Long.class;
        if (targetType == double.class) return valueType == Double.class;
        if (targetType == float.class) return valueType == Float.class;
        if (targetType == boolean.class) return valueType == Boolean.class;
        if (targetType == short.class) return valueType == Short.class;
        if (targetType == byte.class) return valueType == Byte.class;
        if (targetType == char.class) return valueType == Character.class;
        return false;
    }

    @SuppressWarnings("unchecked")
    private T invokeCreator(Creator<T> creator, Object value, JsonParser p, DeserializationContext context) throws IOException {
        try {
            return creator.create(value);
        } catch (Throwable cause) {
            Throwable throwable = cause instanceof InvocationTargetException ? cause.getCause() : cause;
            String msg = String.format("Failed to create %s using %s with value '%s': %s", targetClass.getSimpleName(), creator, value, throwable.getMessage());
            return (T) context.handleInstantiationProblem(targetClass, value, new JsonMappingException(p, msg, throwable));
        }
    }

    private T tryStringConversion(String value, JsonParser p, DeserializationContext context) throws IOException {
        // 首先尝试字符串创建器（如果存在）
        if (stringCreator != null) {
            try {
                return stringCreator.create(value);
            } catch (Throwable ignored) {
                // 忽略异常，尝试其他创建器
            }
        }

        // 尝试所有其他创建器
        for (Creator<T> creator : creators) {
            // 跳过字符串创建器（已经尝试过）
            if (creator == stringCreator) continue;
            Class<?> paramType = creator.getParameterType();
            // 获取或创建字符串转换器
            StringConverter converter = STRING_CONVERTER_CACHE.computeIfAbsent(paramType, UniversalDeserializer::createStringConverter);
            if (converter != null) {
                try {
                    Object converted = converter.convert(value);
                    return creator.create(converted);
                } catch (IllegalArgumentException ignored) {
                    // 转换失败，尝试下一个
                } catch (Throwable e) {
                    throw new JsonMappingException(p, "Error converting string value '" + value + "' to " + paramType.getName(), e);
                }
            }
        }
        throw context.instantiationException(targetClass, "No suitable creator found for string value: " + value);
    }

    private static StringConverter createStringConverter(Class<?> targetType) {
        if (targetType == String.class) {
            return v -> v;
        } else if (targetType == int.class || targetType == Integer.class) {
            return s -> {
                long v = Long.parseLong(s);
                if (v < Integer.MIN_VALUE || v > Integer.MAX_VALUE) {
                    throw new ArithmeticException("Integer overflow");
                }
                return (int) v;
            };
        } else if (targetType == long.class || targetType == Long.class) {
            return s -> {
                try {
                    return Long.parseLong(s);
                } catch (NumberFormatException e) {
                    // 尝试BigInteger转换
                    BigInteger bi = new BigInteger(s);
                    if (bi.compareTo(BigInteger.valueOf(Long.MIN_VALUE)) < 0 || bi.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) {
                        throw new ArithmeticException("Long overflow");
                    }
                    return bi.longValue();
                }
            };
        } else if (targetType == double.class || targetType == Double.class) {
            return Double::parseDouble;
        } else if (targetType == float.class || targetType == Float.class) {
            return s -> {
                double d = Double.parseDouble(s);
                if (d < -Float.MAX_VALUE || d > Float.MAX_VALUE) {
                    throw new ArithmeticException("Float overflow");
                }
                return (float) d;
            };
        } else if (targetType == boolean.class || targetType == Boolean.class) {
            return Boolean::parseBoolean;
        } else if (targetType == BigDecimal.class) {
            return BigDecimal::new;
        } else if (targetType == BigInteger.class) {
            return BigInteger::new;
        } else if (targetType == short.class || targetType == Short.class) {
            return s -> {
                int v = Integer.parseInt(s);
                if (v < Short.MIN_VALUE || v > Short.MAX_VALUE) {
                    throw new ArithmeticException("Short overflow");
                }
                return (short) v;
            };
        } else if (targetType == byte.class || targetType == Byte.class) {
            return s -> {
                int v = Integer.parseInt(s);
                if (v < Byte.MIN_VALUE || v > Byte.MAX_VALUE) {
                    throw new ArithmeticException("Byte overflow");
                }
                return (byte) v;
            };
        } else if (targetType == char.class || targetType == Character.class) {
            return v -> v.isEmpty() ? '\0' : v.charAt(0);
        } else if (targetType.isEnum()) {
            return v -> {
                try {
                    Method method = targetType.getMethod("valueOf", String.class);
                    return method.invoke(null, v);
                } catch (Exception e) {
                    throw new IllegalArgumentException("Invalid enum value: " + v);
                }
            };
        }
        return null;
    }

    private Object getValueBasedOnToken(JsonParser p, JsonToken token, DeserializationContext context) throws IOException {
        switch (token) {
            case VALUE_STRING:
                return p.getText();
            case VALUE_NUMBER_INT:
                switch (p.getNumberType()) {
                    case BIG_INTEGER:
                        return p.getBigIntegerValue();
                    case LONG:
                        return p.getLongValue();
                    default:
                        return p.getIntValue();
                }
            case VALUE_NUMBER_FLOAT:
                switch (p.getNumberType()) {
                    case BIG_DECIMAL:
                        return p.getDecimalValue();
                    case FLOAT:
                        return p.getFloatValue();
                    default:
                        return p.getDoubleValue();
                }
            case VALUE_TRUE:
                return Boolean.TRUE;
            case VALUE_FALSE:
                return Boolean.FALSE;
            case VALUE_NULL:
                return null;
            case VALUE_ENUM:
                return p.getObject();
            case START_OBJECT:
                return context.readValue(p, Map.class);
            case START_ARRAY:
                return context.readValue(p, List.class);
            case VALUE_EMBEDDED_OBJECT:
                return p.getEmbeddedObject();
            default:
                throw new JsonMappingException(p, "Unsupported token for " + targetClass.getSimpleName() + ": " + token);
        }
    }

    private interface Creator<U> {
        U create(Object value) throws Throwable;

        Class<?> getParameterType();
    }

    private static class ConstructorCreator<U> implements Creator<U> {
        private final MethodHandle constructorHandle;
        private final Class<?> paramType;

        ConstructorCreator(Constructor<?> constructor) {
            this.paramType = constructor.getParameterTypes()[0];
            this.constructorHandle = CONSTRUCTOR_HANDLE_CACHE.computeIfAbsent(constructor, c -> {
                try {
                    constructor.setAccessible(true);
                    return MethodHandles.lookup().unreflectConstructor(constructor);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Failed to access constructor: " + constructor, e);
                }
            });
        }

        @SuppressWarnings("unchecked")
        @Override
        public U create(Object value) throws Throwable {
            return (U) constructorHandle.invoke(value);
        }

        @Override
        public Class<?> getParameterType() {
            return paramType;
        }

        @Override
        public String toString() {
            return "Constructor[" + constructorHandle.type().parameterType(0).getName() + "]";
        }
    }

    private static class MethodCreator<U> implements Creator<U> {
        private final MethodHandle methodHandle;
        private final Class<?> paramType;

        MethodCreator(Method method) {
            this.paramType = method.getParameterTypes()[0];
            this.methodHandle = METHOD_HANDLE_CACHE.computeIfAbsent(method, m -> {
                try {
                    method.setAccessible(true);
                    return MethodHandles.lookup().unreflect(m);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Failed to access method: " + method, e);
                }
            });
        }

        @SuppressWarnings("unchecked")
        @Override
        public U create(Object value) throws Throwable {
            return (U) methodHandle.invoke(value);
        }

        @Override
        public Class<?> getParameterType() {
            return paramType;
        }

        @Override
        public String toString() {
            return "Method[" + methodHandle.type().parameterType(1).getName() + "]";
        }
    }

    // 高性能数据结构
    private static class ClassPair {
        private final Class<?> first;
        private final Class<?> second;
        private final int hash;

        ClassPair(Class<?> first, Class<?> second) {
            this.first = first;
            this.second = second;
            this.hash = 31 * first.hashCode() + second.hashCode();
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ClassPair that = (ClassPair) o;
            return first == that.first && second == that.second;
        }

        @Override
        public int hashCode() {
            return hash;
        }
    }

    @FunctionalInterface
    private interface StringConverter {
        Object convert(String value) throws NumberFormatException;
    }
}